<template>
  <iframe
    ref="rich-text-preview"
    frameborder="0"
    width="100%"
    :height="iframHeight"
    :style="{ 'background-color': bg, display: 'block' }"
    v-if="show"
  ></iframe>
</template>

<script>
// 依赖 viewerjs 包， 所以得安装
import 'viewerjs/dist/viewer.css';
import { api } from 'v-viewer'

// 富文本内容实现1:1预览
export default {
  name: 'RichTextPreview',
  props: {
    // 富文本内容
    html: {
      type: String
    },
    // 蒙层的背景颜色
    bg: {
      type: String
    },
    // 点击富文本，是否预览富文本中的图片
    previewImg: {
      type: Boolean,
      default: true
    },
    /**
     * 是否显示滚动条
     * @example
     * "hidden"  横向和竖向都隐藏滚动条
     * "scroll hidden" 横向滚动条展示，竖向的隐藏
     * "hidden scroll" 横向滚动条隐藏， 竖向的展示
     * "scroll" 随内容自适应
     */
    overflow: {
      type: String,
      default: 'auto'
    },

    /**
     * 溢出值； 当少数情况计算不准确，可通过这个属性设置一个较大值
     */
    coverHeight: {
      type: Number,
      default: 0
    },
    /**
     * style的字符串
     */
    cssText: {
      type: String
    },
    /**
     * 样式列表
     */
    linkList: {
      type: Array,
      default: () => []
    },

    /**
     * 默认开启原生图片懒加载
     */
    lazy: {
      type: Boolean,
      default: true
    }
  },
  data () {
    return {
      iframHeight: 'auto',
      bodyDOM: null,
      htmlDOM: null,
      show: false,

      // 定时器准确获取高度
      timer: null,
      onresizeHandler: null,

      // 取最后2次高度，如果一样，说明高度已经没有变化了-解决iframe 中 onload不触发的问题
      heightList: []
    }
  },
  watch: {
    html: {
      handler (val) {
        if (val) {
          this.show = true

          this.$nextTick(() => {
            this.setIframeContent()
          })
        }
      },
      immediate: true
    }
  },
  mounted() {
    this.onresizeHandler = () => {
      this.heightList = []

      this.getMaxHeight()
    }

    window.addEventListener('resize', this.onresizeHandler, false)
  },
  beforeDestroy() {
    if (this.onresizeHandler) {
      window.removeEventListener('resize',this.onresizeHandler)
    }

    if (this.timer) {
      window.clearInterval(this.timer)
    }
  },

  methods: {
    /**
     * 使用iframe实现富文本1：1预览
     */
    setIframeContent () {
      let frame = this.$refs['rich-text-preview']

      this.bodyDOM = frame.contentDocument.querySelector('body')
      this.htmlDOM = frame.contentDocument.querySelector('html')

      this.bodyDOM.addEventListener('click', (event) => {
        if (this.previewImg) {
          this.onPreviewContent(event)
        }

        this.emitEvent(event)
      }, true)


      this.loadStyle()

      // 是否需要支持图片原生懒加载
      if (this.lazy) {
        // 创建一个临时的div
        let tempContainer = document.createElement('div')
        // 将HTML代码片段转为可操作的DOM
        tempContainer.innerHTML = this.html || ''

        let imgList = tempContainer.querySelectorAll('img')

        for (let i = 0, len = imgList.length; i < len; i++) {
          imgList[i].setAttribute('loading', 'lazy')
        }

        this.bodyDOM.appendChild(tempContainer)
      } else {
        this.bodyDOM.innerHTML = this.html || ''
      }

      const getHeightTimerHandler = () => {
        if (this.heightList.length && this.heightList.length> 2) {
          let h1 = this.heightList[this.heightList.length - 1]
          let h2 =  this.heightList[this.heightList.length - 2]

          if (h1 === h2) {
            window.clearInterval(this.timer)

            this.iframHeight = h1
          } else {
            this.getMaxHeight()
          }
        } else {
          this.getMaxHeight()
        }
      }

      this.timer = window.setInterval(getHeightTimerHandler, 100)
    },

    /**
     * 有可能一堆的HTML中是存在 绝对定位的，则高度会存在偏差问题
     */
    getMaxHeight () {
      let bodyHeight = this.bodyDOM.offsetHeight

      let getLastDOM = (list) => {
        let c = list[list.length - 1]

        if (c.children && c.children.length > 1) {
          return getLastDOM(c.children || [])
        } else {
          return c
        }
      }

      let lastDOM = null

      if (this.bodyDOM.children) {
        lastDOM = getLastDOM(this.bodyDOM.children)
      }

      let h = Number.isNaN(Number(this.coverHeight)) ? 0 : this.coverHeight

      if (lastDOM) {
        let lastDOMOffsetTop = lastDOM.offsetTop
        const totalH = Math.max(bodyHeight, lastDOMOffsetTop) + h

        this.heightList.push(totalH);
      } else {
        const totalH = bodyHeight + h

        this.heightList.push(totalH)
      }
    },

    emitEvent (event) {
      this.$emit('click-dom', event)
    },

    onPreviewContent ($event) {
      if ($event.target.nodeName === 'IMG') {
        let url = $event.target.src
        api({
          images: [url]
        })
      }
    },

    /**
     * 加载样式
     */
    loadStyle () {
      let head = this.htmlDOM.querySelector('head')
      let fragment = document.createDocumentFragment()

      this.htmlDOM.style.width = '100%'
      this.htmlDOM.style.height = '100%'
      // 父元素的高度和滚动条替代iframe的滚动条（避免去设置浏览器默认的滚动条样式）
      this.htmlDOM.style.overflow = this.overflow

      this.bodyDOM.style.width = '100%'
      // this.bodyDOM.style.height = '100%'
      this.bodyDOM.style.margin = 0

      if (this.linkList && this.linkList.length) {
        this.linkList.forEach(url => {
          let linkEl = document.createElement('link')

          linkEl.setAttribute('type', 'text/css')
          linkEl.setAttribute('rel', 'stylesheet')
          linkEl.setAttribute('href', url)

          fragment.appendChild(linkEl)
        })
      }

      let styleEl = document.createElement('style')

      let defaultStyle = document.createElement('style')

      // 浏览器滚动条样式
      defaultStyle.innerHTML = `
          /*纯数字换行问题*/
          body {
            word-break: break-all;
            overflow-wrap: break-word;
            -webkit-line-break: after-white-space;
          }
          /*滚动条样式*/
          ::-webkit-scrollbar {
            width: 8px;
            height: 8px;
            background-color: #f5f5f5;
          }

          /*滚动条滑块的样式*/
          ::-webkit-scrollbar-thumb {
             border-radius: 7px;
            border: 3px solid transparent;
            background-color: #d8d8d8;
          }
        `

      // 外部传入的自定义样式
      if (this.cssText) {
        styleEl.innerHTML = this.cssText
      }

      fragment.appendChild(defaultStyle)
      fragment.appendChild(styleEl)

      if (head) {
        head.appendChild(fragment)
      }
    }
  }
}
</script>
